package maple.thelittleredbook.content.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import maple.thelittleredbook.content.dto.*;
import maple.thelittleredbook.interaction.service.AsyncUserBehaviorService;
import maple.thelittleredbook.recommendation.service.ContentFeatureService;
import maple.thelittleredbook.user.entity.User;
import maple.thelittleredbook.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import maple.thelittleredbook.content.entity.Content;
import maple.thelittleredbook.content.entity.ContentOperationLog;
import maple.thelittleredbook.content.entity.Image;
import maple.thelittleredbook.content.entity.Video;
import maple.thelittleredbook.content.mapper.ContentMapper;
import maple.thelittleredbook.content.mapper.ImageMapper;
import maple.thelittleredbook.content.mapper.VideoMapper;
import maple.thelittleredbook.common.exception.BusinessException;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 内容服务类 - 修复版本
 */
@Slf4j
@Service
public class ContentService {

    private final ContentMapper contentMapper;
    private final ImageMapper imageMapper;
    private final VideoMapper videoMapper;
    private final AsyncFileService asyncFileService;
    private final ContentOperationLogService operationLogService;
    private final ContentFeatureService contentFeatureService;
    private final UserMapper userMapper;
    private final AsyncUserBehaviorService asyncUserBehaviorService;

    @Value("${file.server.url}")
    private String fileServerUrl;

    @Autowired
    public ContentService(ContentMapper contentMapper,
                          ImageMapper imageMapper,
                          VideoMapper videoMapper,
                          AsyncFileService asyncFileService,
                          ContentOperationLogService operationLogService,
                          ContentFeatureService contentFeatureService,
                          UserMapper userMapper,
                          AsyncUserBehaviorService asyncUserBehaviorService) {
        this.contentMapper = contentMapper;
        this.imageMapper = imageMapper;
        this.videoMapper = videoMapper;
        this.asyncFileService = asyncFileService;
        this.operationLogService = operationLogService;
        this.contentFeatureService = contentFeatureService;
        this.userMapper = userMapper;
        this.asyncUserBehaviorService = asyncUserBehaviorService;
    }

    /**
     * 创建内容 - 修复版本
     */
    @Transactional
    public ContentCreateResponseDTO createContent(Long userId, String contentType, String title,
                                                  String textContent, MultipartFile cover,
                                                  MultipartFile[] images, MultipartFile video) {
        try {
            log.info("开始创建内容，用户ID: {}, 内容类型: [{}], 标题: {}", userId, contentType, title);

            // 1. 参数验证
            validateCreateRequest(contentType, cover, images, video);

            // 2. 创建内容记录
            Content content = buildContentEntity(userId, contentType, title, textContent);
            contentMapper.insert(content);
            Long contentId = content.getId();

            // 2.5 创建内容特征记录并触发特征生成
            contentFeatureService.createContentFeature(contentId);

            // 3. 设置正确的封面URL并更新
            String coverUrl = fileServerUrl + "/files-get/springboot/littleRedBook/content/" + contentId + "/cover.jpg";
            content.setCoverUrl(coverUrl);
            contentMapper.updateById(content);

            log.info("内容记录创建成功，内容ID: {}", contentId);

            // 4. 插入图片/视频记录到数据库并收集信息
            Map<String, Object> mediaInfo = insertMediaRecords(contentId, contentType, images, video);

            // 5. 处理文件上传（修复后的逻辑）
            processFileUploadsWithOperationLog(contentId, contentType, cover, images, video, mediaInfo, userId);

            // 6. 构建响应
            return buildCreateResponse(content, mediaInfo);

        } catch (IllegalArgumentException e) {
            log.error("创建内容参数错误，用户ID: {}, 错误: {}", userId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("创建内容失败，用户ID: {}", userId, e);
            throw new BusinessException("创建内容失败: " + e.getMessage());
        }
    }

    /**
     * 处理文件上传并创建操作日志 - 修复版本
     */
    private void processFileUploadsWithOperationLog(Long contentId, String contentType, MultipartFile cover,
                                                    MultipartFile[] images, MultipartFile video,
                                                    Map<String, Object> mediaInfo, Long userId) {

        // 更新状态为上传中
        updateContentUploadStatus(contentId, "UPLOADING");

        // 处理封面上传（二选一：用户自定义 OR 默认封面）
        if (cover != null && !cover.isEmpty()) {
            // 有用户自定义封面，上传用户封面
            processUserCoverUpload(contentId, cover, userId);
        } else {
            // 没有用户自定义封面，上传默认封面
            processDefaultCoverUpload(contentId, userId);
        }

        // 根据内容类型处理媒体文件
        if ("IMAGE".equals(contentType)) {
            processImageUploads(contentId, images, mediaInfo, userId);
        } else if ("VIDEO".equals(contentType)) {
            processVideoUpload(contentId, video, mediaInfo, userId);
        }
    }

    /**
     * 处理用户自定义封面上传
     */
    private void processUserCoverUpload(Long contentId, MultipartFile cover, Long userId) {
        try {
            String tempCoverPath = saveTempFile(cover, "cover_" + contentId + "_" + System.currentTimeMillis());
            log.info("用户封面临时文件保存成功: {}", tempCoverPath);

            // 创建操作日志
            Long coverLogId = operationLogService.createOperationLog(
                    contentId, ContentOperationLog.UPLOAD_COVER, 1, userId);

            // 异步上传用户自定义封面
            asyncFileService.uploadCoverFromTempAsync(contentId, tempCoverPath, coverLogId);

        } catch (IOException e) {
            log.error("保存用户封面临时文件失败，内容ID: {}", contentId, e);
            updateContentUploadStatus(contentId, "FAILED");
        }
    }

    /**
     * 处理默认封面上传
     */
    private void processDefaultCoverUpload(Long contentId, Long userId) {
        // 创建操作日志
        Long defaultCoverLogId = operationLogService.createOperationLog(
                contentId, ContentOperationLog.UPLOAD_COVER, 1, userId);

        // 异步上传默认封面
        asyncFileService.uploadDefaultCoverAsync(contentId, defaultCoverLogId);
    }

    /**
     * 处理图片上传
     */
    private void processImageUploads(Long contentId, MultipartFile[] images, Map<String, Object> mediaInfo, Long userId) {
        if (images != null && images.length > 0) {
            try {
                List<String> tempImagePaths = new ArrayList<>();
                List<String> imageIds = (List<String>) mediaInfo.get("imageIds");

                for (int i = 0; i < images.length; i++) {
                    MultipartFile image = images[i];
                    if (image != null && !image.isEmpty() && i < imageIds.size()) {
                        String tempPath = saveTempFile(image, "image_" + imageIds.get(i));
                        tempImagePaths.add(tempPath);
                    }
                }

                if (!tempImagePaths.isEmpty()) {
                    log.info("图片临时文件保存成功，数量: {}", tempImagePaths.size());

                    // 创建操作日志（注意：这里的操作数是图片的数量）
                    Long imagesLogId = operationLogService.createOperationLog(
                            contentId, ContentOperationLog.UPLOAD_IMAGES, tempImagePaths.size(), userId);

                    asyncFileService.uploadImagesFromTempAsync(contentId, tempImagePaths, imageIds, imagesLogId);
                }
            } catch (IOException e) {
                log.error("保存图片临时文件失败，内容ID: {}", contentId, e);
                updateContentUploadStatus(contentId, "FAILED");
            }
        }
    }

    /**
     * 处理视频上传
     */
    private void processVideoUpload(Long contentId, MultipartFile video, Map<String, Object> mediaInfo, Long userId) {
        if (video != null && !video.isEmpty()) {
            try {
                String videoId = (String) mediaInfo.get("videoId");
                String tempVideoPath = saveTempFile(video, "video_" + videoId);
                log.info("视频临时文件保存成功: {}", tempVideoPath);

                // 创建操作日志
                Long videoLogId = operationLogService.createOperationLog(
                        contentId, ContentOperationLog.UPLOAD_VIDEO, 1, userId);

                asyncFileService.uploadVideoFromTempAsync(contentId, tempVideoPath, videoId, videoLogId);
            } catch (IOException e) {
                log.error("保存视频临时文件失败，内容ID: {}", contentId, e);
                updateContentUploadStatus(contentId, "FAILED");
            }
        }
    }

    /**
     * 更新封面
     */
    @Transactional
    public void updateCover(Long contentId, MultipartFile cover, Long userId) {
        try {
            log.info("开始更新封面，内容ID: {}, 用户ID: {}", contentId, userId);

            // 1. 权限验证和状态检查
            Content content = validateContentAccess(contentId, userId);

            // 2. 文件格式验证
            if (cover == null || cover.isEmpty()) {
                throw new IllegalArgumentException("请选择要上传的封面文件");
            }
            asyncFileService.validateImageFile(cover);

            // 3. 原子性状态更新（关键改进）
            int updated = contentMapper.updateStatusIfAllowed(
                    contentId,
                    Arrays.asList("COMPLETED", "FAILED"),
                    "UPDATING"
            );

            if (updated == 0) {
                throw new BusinessException("内容正在处理中，请稍后再试");
            }

            // 4. 创建操作日志
            Long operationLogId = operationLogService.createOperationLog(
                    contentId, ContentOperationLog.UPDATE_COVER, 1, userId);

            // 5. 保存临时文件并异步处理
            try {
                String tempCoverPath = saveTempFile(cover, "update_cover_" + contentId + "_" + System.currentTimeMillis());
                log.info("封面临时文件保存成功: {}", tempCoverPath);

                // 异步执行封面更新
                asyncFileService.updateCoverAsync(contentId, tempCoverPath, operationLogId);

            } catch (IOException e) {
                log.error("保存封面临时文件失败，内容ID: {}", contentId, e);
                operationLogService.markOperationFailed(operationLogId, "保存临时文件失败: " + e.getMessage());
                updateContentUploadStatus(contentId, "FAILED");
                throw new BusinessException("保存临时文件失败");
            }

            log.info("封面更新任务已提交，内容ID: {}, 操作日志ID: {}", contentId, operationLogId);

        } catch (IllegalArgumentException e) {
            log.error("更新封面参数错误，内容ID: {}, 错误: {}", contentId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新封面失败，内容ID: {}", contentId, e);
            throw new BusinessException("更新封面失败: " + e.getMessage());
        }
    }


    /**
     * 更新视频
     */
    @Transactional
    public void updateVideo(Long contentId, MultipartFile video, Long userId) {
        try {
            log.info("开始更新视频，内容ID: {}, 用户ID: {}", contentId, userId);

            // 1. 权限验证和状态检查
            Content content = validateContentAccess(contentId, userId);

            // 2. 内容类型验证
            if (!"VIDEO".equals(content.getContentType())) {
                throw new IllegalArgumentException("只有视频内容才能更新视频文件");
            }

            // 3. 文件格式验证
            if (video == null || video.isEmpty()) {
                throw new IllegalArgumentException("请选择要上传的视频文件");
            }
            asyncFileService.validateVideoFile(video);

            // 4. 原子性状态更新（关键改进）
            int updated = contentMapper.updateStatusIfAllowed(
                    contentId,
                    Arrays.asList("COMPLETED", "FAILED"),
                    "UPDATING"
            );

            if (updated == 0) {
                throw new BusinessException("内容正在处理中，请稍后再试");
            }

            // 5. 创建操作日志
            Long operationLogId = operationLogService.createOperationLog(
                    contentId, ContentOperationLog.UPDATE_VIDEO, 1, userId);

            // 6. 保存临时文件并异步处理
            try {
                String tempVideoPath = saveTempFile(video, "update_video_" + contentId + "_" + System.currentTimeMillis());
                log.info("视频临时文件保存成功: {}", tempVideoPath);

                // 异步执行视频更新
                asyncFileService.updateVideoAsync(contentId, tempVideoPath, operationLogId);

            } catch (IOException e) {
                log.error("保存视频临时文件失败，内容ID: {}", contentId, e);
                operationLogService.markOperationFailed(operationLogId, "保存临时文件失败: " + e.getMessage());
                updateContentUploadStatus(contentId, "FAILED");
                throw new BusinessException("保存临时文件失败");
            }

            log.info("视频更新任务已提交，内容ID: {}, 操作日志ID: {}", contentId, operationLogId);

        } catch (IllegalArgumentException e) {
            log.error("更新视频参数错误，内容ID: {}, 错误: {}", contentId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新视频失败，内容ID: {}", contentId, e);
            throw new BusinessException("更新视频失败: " + e.getMessage());
        }
    }


    /**
     * 批量更新图片 - 修复版本，参考创建逻辑
     */
    @Transactional
    public void updateImages(Long contentId, List<Long> deleteImageIds, MultipartFile[] newImages, Long userId) {
        try {
            log.info("开始批量更新图片，内容ID: {}, 用户ID: {}, 删除数量: {}, 新增数量: {}",
                    contentId, userId,
                    deleteImageIds != null ? deleteImageIds.size() : 0,
                    newImages != null ? newImages.length : 0);

            // 1. 权限验证和状态检查
            Content content = validateContentAccess(contentId, userId);

            // 2. 内容类型验证
            if (!"IMAGE".equals(content.getContentType())) {
                throw new IllegalArgumentException("只有图片内容才能更新图片文件");
            }

            // 3. 参数验证
            validateImagesUpdateRequest(contentId, deleteImageIds, newImages);

            // 4. 原子性状态更新（关键改进）
            int updated = contentMapper.updateStatusIfAllowed(
                    contentId,
                    Arrays.asList("COMPLETED", "FAILED"),
                    "UPDATING"
            );

            if (updated == 0) {
                throw new BusinessException("内容正在处理中，请稍后再试");
            }

            // 5. 计算总操作数并创建操作日志
            int totalOperations = 0;
            if (deleteImageIds != null) {
                totalOperations += deleteImageIds.size();
            }

            // 预处理新图片文件，保存到临时目录（关键修复）
            List<String> tempImagePaths = new ArrayList<>();
            List<String> newImageIds = new ArrayList<>();

            if (newImages != null) {
                for (MultipartFile newImage : newImages) {
                    if (newImage != null && !newImage.isEmpty()) {
                        try {
                            String newImageId = UUID.randomUUID().toString();
                            String tempPath = saveTempFile(newImage, "update_image_" + newImageId + "_" + System.currentTimeMillis());
                            tempImagePaths.add(tempPath);
                            newImageIds.add(newImageId);
                            totalOperations++;
                            log.info("图片临时文件保存成功: {} -> {}", newImage.getOriginalFilename(), tempPath);
                        } catch (IOException e) {
                            log.error("保存图片临时文件失败，文件: {}", newImage.getOriginalFilename(), e);
                            throw new BusinessException("保存临时文件失败: " + e.getMessage());
                        }
                    }
                }
            }

            Long operationLogId = operationLogService.createOperationLog(
                    contentId, ContentOperationLog.UPDATE_IMAGES, totalOperations, userId);

            // 6. 异步执行批量操作（传递临时文件路径而不是 MultipartFile）
            asyncFileService.updateImagesWithTempFilesAsync(contentId, deleteImageIds, tempImagePaths, newImageIds, operationLogId);

            log.info("图片批量更新任务已提交，内容ID: {}, 操作日志ID: {}, 实际新增图片数: {}",
                    contentId, operationLogId, tempImagePaths.size());

        } catch (IllegalArgumentException e) {
            log.error("批量更新图片参数错误，内容ID: {}, 错误: {}", contentId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量更新图片失败，内容ID: {}", contentId, e);
            throw new BusinessException("批量更新图片失败: " + e.getMessage());
        }
    }

    /**
     * 验证图片批量更新请求
     */
    private void validateImagesUpdateRequest(Long contentId, List<Long> deleteImageIds, MultipartFile[] newImages) {
        // 检查是否至少有一个操作
        boolean hasDeleteOperation = deleteImageIds != null && !deleteImageIds.isEmpty();
        boolean hasUploadOperation = newImages != null && newImages.length > 0;

        if (!hasDeleteOperation && !hasUploadOperation) {
            throw new IllegalArgumentException("请至少指定删除图片或上传新图片");
        }

        // 验证删除的图片ID
        if (hasDeleteOperation) {
            for (Long imageId : deleteImageIds) {
                Image image = imageMapper.selectByImageId(imageId);
                if (image == null) {
                    throw new IllegalArgumentException("图片ID " + imageId + " 不存在");
                }
                if (!image.getContentId().equals(contentId)) {
                    throw new IllegalArgumentException("图片ID " + imageId + " 不属于当前内容");
                }
            }
        }

        // 验证新图片文件
        if (hasUploadOperation) {
            for (MultipartFile newImage : newImages) {
                if (newImage != null && !newImage.isEmpty()) {
                    asyncFileService.validateImageFile(newImage);
                }
            }
        }

        // 验证操作后的图片总数不超过8张
        Long currentImageCount = imageMapper.countByContentId(contentId);
        int deleteCount = hasDeleteOperation ? deleteImageIds.size() : 0;
        int addCount = 0;
        if (hasUploadOperation) {
            addCount = (int) Arrays.stream(newImages)
                    .filter(img -> img != null && !img.isEmpty())
                    .count();
        }

        long finalImageCount = currentImageCount - deleteCount + addCount;
        if (finalImageCount > 8) {
            throw new IllegalArgumentException("操作后图片总数不能超过8张，当前: " + currentImageCount +
                    ", 删除: " + deleteCount + ", 新增: " + addCount);
        }
    }


    /**
     * 查询内容的媒体文件
     */
    public ContentMediaDTO getContentMedia(Long contentId, Long userId) {
        log.info("查询内容媒体文件，内容ID: {}, 用户ID: {}", contentId, userId);

        // 权限验证
        Content content = validateContentAccess(contentId, userId);

        ContentMediaDTO mediaDTO = new ContentMediaDTO();
        mediaDTO.setContentId(contentId);
        mediaDTO.setContentType(content.getContentType());
        mediaDTO.setCoverUrl(content.getCoverUrl());

        // 查询图片列表
        List<Image> images = imageMapper.selectByContentId(contentId);
        List<ContentMediaDTO.ImageDTO> imageDTOs = images.stream()
                .map(image -> {
                    ContentMediaDTO.ImageDTO dto = new ContentMediaDTO.ImageDTO();
                    dto.setId(image.getId());
                    dto.setImageUrl(image.getImageUrl());
                    dto.setCreatedAt(image.getCreatedAt());
                    return dto;
                })
                .collect(Collectors.toList());
        mediaDTO.setImages(imageDTOs);

        // 查询视频列表
        List<Video> videos = videoMapper.selectByContentId(contentId);
        List<ContentMediaDTO.VideoDTO> videoDTOs = videos.stream()
                .map(video -> {
                    ContentMediaDTO.VideoDTO dto = new ContentMediaDTO.VideoDTO();
                    dto.setId(video.getId());
                    dto.setVideoUrl(video.getVideoUrl());
                    dto.setCreatedAt(video.getCreatedAt());
                    return dto;
                })
                .collect(Collectors.toList());
        mediaDTO.setVideos(videoDTOs);

        return mediaDTO;
    }

    /**
     * 查询操作状态
     */
    public OperationStatusDTO getOperationStatus(Long contentId, Long operationId, Long userId) {
        log.info("查询操作状态，内容ID: {}, 操作ID: {}, 用户ID: {}", contentId, operationId, userId);

        // 权限验证
        validateContentAccess(contentId, userId);

        // 查询操作日志
        ContentOperationLog operationLog = operationLogService.getOperationLog(operationId);
        if (operationLog == null) {
            throw new IllegalArgumentException("操作记录不存在");
        }

        if (!operationLog.getContentId().equals(contentId)) {
            throw new IllegalArgumentException("操作记录与内容不匹配");
        }

        // 构建响应DTO
        OperationStatusDTO statusDTO = new OperationStatusDTO();
        statusDTO.setOperationId(operationLog.getId());
        statusDTO.setContentId(operationLog.getContentId());
        statusDTO.setOperationType(operationLog.getOperationType());
        statusDTO.setOperationStatus(operationLog.getOperationStatus());
        statusDTO.setTotalOperations(operationLog.getTotalOperations());
        statusDTO.setCompletedOperations(operationLog.getCompletedOperations());
        statusDTO.setErrorMessage(operationLog.getErrorMessage());
        statusDTO.setStartedAt(operationLog.getStartedAt());
        statusDTO.setCompletedAt(operationLog.getCompletedAt());

        // 计算进度百分比
        if (operationLog.getTotalOperations() > 0) {
            double progress = (double) operationLog.getCompletedOperations() / operationLog.getTotalOperations() * 100;
            statusDTO.setProgressPercentage(Math.round(progress * 100.0) / 100.0); // 保留两位小数
        } else {
            statusDTO.setProgressPercentage(0.0);
        }

        return statusDTO;
    }

    /**
     * 验证内容是否可以进行更新操作
     */
    private Content validateContentForUpdate(Long contentId, Long userId) {
        // 查询内容记录
        Content content = contentMapper.selectById(contentId);
        if (content == null) {
            throw new IllegalArgumentException("内容不存在");
        }

        // 检查内容是否已被删除
        if (Boolean.FALSE.equals(content.getIsPublished())) {
            throw new IllegalArgumentException("已删除的内容不能修改");
        }

        // 权限验证：只有内容所有者可以修改
        if (!content.getUserId().equals(userId)) {
            throw new IllegalArgumentException("无权限修改此内容");
        }

        // 状态检查：不能在处理中时进行修改
        String currentStatus = content.getUploadStatus();
        if (!"COMPLETED".equals(currentStatus) && !"FAILED".equals(currentStatus)) {
            throw new IllegalArgumentException("内容正在处理中，请稍后再试。当前状态: " + currentStatus);
        }

        // 检查是否有正在进行的操作
        if (operationLogService.hasProcessingOperations(contentId)) {
            throw new IllegalArgumentException("内容有正在进行的操作，请稍后再试");
        }

        return content;
    }

    /**
     * 验证内容访问权限 - 修改版本（如果需要包含删除状态检查）
     */
    public Content validateContentAccess(Long contentId, Long userId) {
        Content content = contentMapper.selectById(contentId);
        if (content == null) {
            throw new IllegalArgumentException("内容不存在");
        }

        // 检查内容是否已被删除
        if (Boolean.FALSE.equals(content.getIsPublished())) {
            throw new IllegalArgumentException("内容已被删除");
        }

        // 只有内容所有者可以查看详细信息
        if (!content.getUserId().equals(userId)) {
            throw new IllegalArgumentException("无权限访问此内容");
        }

        return content;
    }


    /**
     * 获取用户自己的内容列表
     *
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @param title 标题筛选
     * @param textContent 内容筛选
     * @param contentType 内容类型筛选
     * @param orderBy 排序方式
     * @param userId 用户ID
     * @return 内容列表
     */
    public ContentListResponse getUserContentList(Integer pageNum, Integer pageSize,
                                                  String title, String textContent, String contentType,
                                                  String orderBy, Long userId) {
        // 1. 参数验证和默认值设置
        pageNum = pageNum != null && pageNum > 0 ? pageNum : 1;
        pageSize = pageSize != null && pageSize > 0 && pageSize <= 100 ? pageSize : 20;
        title = title != null && !title.trim().isEmpty() ? title : "all";
        textContent = textContent != null && !textContent.trim().isEmpty() ? textContent : "all";
        contentType = contentType != null && !contentType.trim().isEmpty() ? contentType : "all";
        orderBy = orderBy != null && !orderBy.trim().isEmpty() ? orderBy : "created_at";

        log.info("查询用户内容列表，用户ID: {}, 页码: {}, 每页数量: {}, 标题: {}, 内容: {}, 类型: {}, 排序: {}",
                userId, pageNum, pageSize, title, textContent, contentType, orderBy);

        // 2. 创建分页对象
        Page<ContentListItemDTO> page = new Page<>(pageNum, pageSize);

        // 3. 处理筛选参数
        String finalTitle = "all".equals(title) ? null : title;
        String finalTextContent = "all".equals(textContent) ? null : textContent;
        String finalContentType = "all".equals(contentType) ? null : contentType;
        String finalOrderBy = "like_count".equals(orderBy) ? "like_count" : "created_at";

        // 4. 查询数据库
        IPage<ContentListItemDTO> result = contentMapper.selectUserContentList(
                page, userId, finalTitle, finalTextContent, finalContentType, finalOrderBy);

        // 5. 用户查看自己的内容列表不需要设置点赞状态（自己的内容默认不显示点赞状态）
        for (ContentListItemDTO content : result.getRecords()) {
            content.setIsLiked(false);
        }

        // 6. 构建响应对象
        return buildContentListResponse(result, pageNum, pageSize);
    }

    /**
     * 获取所有内容列表（管理员使用）
     *
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @param title 标题筛选
     * @param textContent 内容筛选
     * @param contentType 内容类型筛选
     * @param orderBy 排序方式
     * @param userId 用户ID筛选
     * @param currentUserId 当前登录用户ID（用于查询点赞状态）
     * @return 内容列表
     */
    public ContentListResponse getAdminContentList(Integer pageNum, Integer pageSize,
                                                   String title, String textContent, String contentType,
                                                   String orderBy, Long userId, Long currentUserId) {
        // 1. 参数验证和默认值设置
        pageNum = pageNum != null && pageNum > 0 ? pageNum : 1;
        pageSize = pageSize != null && pageSize > 0 && pageSize <= 100 ? pageSize : 20;
        title = title != null && !title.trim().isEmpty() ? title : "all";
        textContent = textContent != null && !textContent.trim().isEmpty() ? textContent : "all";
        contentType = contentType != null && !contentType.trim().isEmpty() ? contentType : "all";
        orderBy = orderBy != null && !orderBy.trim().isEmpty() ? orderBy : "created_at";

        log.info("管理员查询内容列表，页码: {}, 每页数量: {}, 标题: {}, 内容: {}, 类型: {}, 排序: {}, 用户ID: {}, 当前用户ID: {}",
                pageNum, pageSize, title, textContent, contentType, orderBy, userId, currentUserId);

        // 2. 创建分页对象
        Page<ContentListItemDTO> page = new Page<>(pageNum, pageSize);

        // 3. 处理筛选参数
        String finalTitle = "all".equals(title) ? null : title;
        String finalTextContent = "all".equals(textContent) ? null : textContent;
        String finalContentType = "all".equals(contentType) ? null : contentType;
        String finalOrderBy = "like_count".equals(orderBy) ? "like_count" : "created_at";

        // 4. 查询数据库
        IPage<ContentListItemDTO> result = contentMapper.selectAdminContentList(
                page, userId, finalTitle, finalTextContent, finalContentType, finalOrderBy);

        // 5. 设置点赞状态
        if (currentUserId != null) {
            setContentListLikeStatus(result.getRecords(), currentUserId);
        }

        // 6. 构建响应对象
        return buildContentListResponse(result, pageNum, pageSize);
    }

    /**
     * 获取公开内容列表（用户查看所有公开内容）
     *
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @param title 标题筛选
     * @param textContent 内容筛选
     * @param contentType 内容类型筛选
     * @param orderBy 排序方式
     * @param userId 用户ID筛选
     * @param currentUserId 当前登录用户ID（用于查询点赞状态）
     * @return 内容列表
     */
    public ContentListResponse getPublicContentList(Integer pageNum, Integer pageSize,
                                                    String title, String textContent, String contentType,
                                                    String orderBy, Long userId, Long currentUserId) {
        // 1. 参数验证和默认值设置
        pageNum = pageNum != null && pageNum > 0 ? pageNum : 1;
        pageSize = pageSize != null && pageSize > 0 && pageSize <= 100 ? pageSize : 20;
        title = title != null && !title.trim().isEmpty() ? title : "all";
        textContent = textContent != null && !textContent.trim().isEmpty() ? textContent : "all";
        contentType = contentType != null && !contentType.trim().isEmpty() ? contentType : "all";
        orderBy = orderBy != null && !orderBy.trim().isEmpty() ? orderBy : "created_at";

        log.info("查询公开内容列表，页码: {}, 每页数量: {}, 标题: {}, 内容: {}, 类型: {}, 排序: {}, 用户ID: {}, 当前用户ID: {}",
                pageNum, pageSize, title, textContent, contentType, orderBy, userId, currentUserId);

        // 2. 创建分页对象
        Page<ContentListItemDTO> page = new Page<>(pageNum, pageSize);

        // 3. 处理筛选参数
        String finalTitle = "all".equals(title) ? null : title;
        String finalTextContent = "all".equals(textContent) ? null : textContent;
        String finalContentType = "all".equals(contentType) ? null : contentType;
        String finalOrderBy = "like_count".equals(orderBy) ? "like_count" : "created_at";

        // 4. 查询数据库
        IPage<ContentListItemDTO> result = contentMapper.selectPublicContentList(
                page, userId, finalTitle, finalTextContent, finalContentType, finalOrderBy);

        // 5. 设置点赞状态
        if (currentUserId != null) {
            setContentListLikeStatus(result.getRecords(), currentUserId);
        }

        // 6. 构建响应对象
        return buildContentListResponse(result, pageNum, pageSize);
    }

    /**
     * 为内容列表设置点赞状态
     */
    private void setContentListLikeStatus(List<ContentListItemDTO> contents, Long currentUserId) {
        for (ContentListItemDTO content : contents) {
            try {
                boolean isLiked = asyncUserBehaviorService.getLikeStatus(currentUserId, content.getId(), "CONTENT") != null;
                content.setIsLiked(isLiked);
            } catch (Exception e) {
                log.warn("查询内容点赞状态失败，内容ID: {}, 用户ID: {}", content.getId(), currentUserId, e);
                content.setIsLiked(false); // 默认为未点赞
            }
        }
    }


    /**
     * 更新内容的标题和文本内容
     */
    @Transactional
    public void updateContentText(Long contentId, String title, String textContent, Long userId) {
        try {
            log.info("开始更新内容文本，内容ID: {}, 用户ID: {}, 标题: {}", contentId, userId, title);

            // 1. 权限验证和状态检查
            Content content = validateContentForUpdate(contentId, userId);

            // 2. 更新数据库
            int updated = contentMapper.updateContentText(contentId, title, textContent);
            if (updated == 0) {
                throw new BusinessException("更新失败，内容可能不存在");
            }

            // 3. 重置内容特征状态为待处理
            contentFeatureService.resetContentFeatureToPending(contentId);

            log.info("内容文本更新成功，内容ID: {}, 标题: {}", contentId, title);

        } catch (IllegalArgumentException e) {
            log.error("更新内容文本参数错误，内容ID: {}, 错误: {}", contentId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新内容文本失败，内容ID: {}", contentId, e);
            throw new BusinessException("更新内容文本失败: " + e.getMessage());
        }
    }

    /**
     * 更新内容发布状态（软删除）
     */
    @Transactional
    public void updatePublishStatus(Long contentId, Boolean isPublished, Long userId, boolean isAdmin) {
        try {
            log.info("开始更新发布状态，内容ID: {}, 用户ID: {}, 发布状态: {}, 是否管理员: {}",
                    contentId, userId, isPublished, isAdmin);

            // 1. 查询内容记录
            Content content = contentMapper.selectById(contentId);
            if (content == null) {
                throw new IllegalArgumentException("内容不存在");
            }

            // 2. 权限验证
            boolean isOwner = content.getUserId().equals(userId);

            if (!isAdmin && !isOwner) {
                throw new IllegalArgumentException("无权限修改此内容");
            }

            // 3. 业务规则验证
            if (Boolean.TRUE.equals(isPublished)) {
                // 不允许将已删除的内容恢复发布
                throw new IllegalArgumentException("已删除的内容不能恢复发布");
            }

            if (Boolean.FALSE.equals(isPublished) && Boolean.FALSE.equals(content.getIsPublished())) {
                // 内容已经是删除状态
                throw new IllegalArgumentException("内容已处于删除状态");
            }

            // 4. 更新数据库
            int updated = contentMapper.updatePublishStatus(contentId, isPublished);
            if (updated == 0) {
                throw new BusinessException("更新失败，内容可能不存在");
            }

            String action = isAdmin ? "管理员删除" : "用户删除";
            log.info("内容{}成功，内容ID: {}, 操作者: {}", action, contentId, userId);

        } catch (IllegalArgumentException e) {
            log.error("更新发布状态参数错误，内容ID: {}, 错误: {}", contentId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新发布状态失败，内容ID: {}", contentId, e);
            throw new BusinessException("更新发布状态失败: " + e.getMessage());
        }
    }


    /**
     * 构建内容列表响应对象
     */
    private ContentListResponse buildContentListResponse(IPage<ContentListItemDTO> result, Integer pageNum, Integer pageSize) {
        ContentListResponse response = new ContentListResponse();
        response.setTotal(result.getTotal());
        response.setTotalPages((int) Math.ceil((double) result.getTotal() / pageSize));
        response.setPageNum(pageNum);
        response.setPageSize(pageSize);
        response.setContents(result.getRecords());

        log.info("内容列表查询完成，总记录数: {}, 当前页记录数: {}", result.getTotal(), result.getRecords().size());

        return response;
    }


    /**
     * 浏览内容详情
     * 异步记录用户行为并更新相关数据
     *
     * @param contentId 内容ID
     * @param userId 用户ID
     * @return 内容详情DTO
     */
    public ContentViewDTO viewContent(Long contentId, Long userId) {
        try {
            log.info("用户浏览内容，用户ID: {}, 内容ID: {}", userId, contentId);

            // 1. 查询内容基本信息
            Content content = contentMapper.selectById(contentId);
            if (content == null) {
                throw new IllegalArgumentException("内容不存在");
            }

            // 2. 检查内容是否已发布
            if (Boolean.FALSE.equals(content.getIsPublished())) {
                throw new IllegalArgumentException("内容已被删除或未发布");
            }

            // 3. 查询发布用户信息
            User contentUser = userMapper.selectById(content.getUserId());

            // 4. 构建基本响应DTO
            ContentViewDTO viewDTO = buildContentViewDTO(content, contentUser);

            // 5. 查询并设置媒体文件信息
            setMediaFiles(viewDTO, contentId);

            // 6. 设置用户点赞状态
            if (userId != null) {
                try {
                    boolean isLiked = asyncUserBehaviorService.getLikeStatus(userId, contentId, "CONTENT") != null;
                    viewDTO.setIsLiked(isLiked);
                } catch (Exception e) {
                    log.warn("查询内容点赞状态失败，内容ID: {}, 用户ID: {}", contentId, userId, e);
                    viewDTO.setIsLiked(false); // 默认为未点赞
                }
            } else {
                viewDTO.setIsLiked(false); // 未登录用户默认为未点赞
            }

            // 7. 异步处理用户行为（记录浏览行为 + 更新浏览量 + 更新用户画像）
            if (userId != null) {
                asyncUserBehaviorService.processViewBehaviorAsync(userId, contentId);
            }

            log.debug("内容浏览处理完成，用户ID: {}, 内容ID: {}", userId, contentId);
            return viewDTO;

        } catch (IllegalArgumentException e) {
            log.warn("浏览内容参数错误，用户ID: {}, 内容ID: {}, 错误: {}", userId, contentId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("浏览内容失败，用户ID: {}, 内容ID: {}", userId, contentId, e);
            throw new BusinessException("浏览内容失败: " + e.getMessage());
        }
    }

    /**
     * 构建内容浏览DTO
     */
    private ContentViewDTO buildContentViewDTO(Content content, User contentUser) {
        ContentViewDTO viewDTO = new ContentViewDTO();
        viewDTO.setId(content.getId());
        viewDTO.setUserId(content.getUserId());
        viewDTO.setContentType(content.getContentType());
        viewDTO.setTitle(content.getTitle());
        viewDTO.setTextContent(content.getTextContent());
        viewDTO.setCoverUrl(content.getCoverUrl());
        viewDTO.setLikeCount(content.getLikeCount());
        viewDTO.setCommentCount(content.getCommentCount());
        viewDTO.setViewCount(content.getViewCount());
        viewDTO.setIsPublished(content.getIsPublished());
        viewDTO.setCreatedAt(content.getCreatedAt());
        viewDTO.setUpdatedAt(content.getUpdatedAt());

        // 设置用户信息
        if (contentUser != null) {
            viewDTO.setUsername(contentUser.getUsername());
            viewDTO.setUserAvatar(contentUser.getAvatar());
        }

        return viewDTO;
    }

    /**
     * 设置媒体文件信息
     */
    private void setMediaFiles(ContentViewDTO viewDTO, Long contentId) {
        // 查询图片列表
        List<Image> images = imageMapper.selectByContentId(contentId);
        List<ContentViewDTO.ImageDTO> imageDTOs = images.stream()
                .map(image -> {
                    ContentViewDTO.ImageDTO dto = new ContentViewDTO.ImageDTO();
                    dto.setId(image.getId());
                    dto.setImageUrl(image.getImageUrl());
                    dto.setCreatedAt(image.getCreatedAt());
                    return dto;
                })
                .collect(Collectors.toList());
        viewDTO.setImages(imageDTOs);

        // 查询视频列表
        List<Video> videos = videoMapper.selectByContentId(contentId);
        List<ContentViewDTO.VideoDTO> videoDTOs = videos.stream()
                .map(video -> {
                    ContentViewDTO.VideoDTO dto = new ContentViewDTO.VideoDTO();
                    dto.setId(video.getId());
                    dto.setVideoUrl(video.getVideoUrl());
                    dto.setCreatedAt(video.getCreatedAt());
                    return dto;
                })
                .collect(Collectors.toList());
        viewDTO.setVideos(videoDTOs);
    }


    // ================================ 保持原有的私有方法 ================================

    /**
     * 验证创建请求参数
     */
    private void validateCreateRequest(String contentType, MultipartFile cover,
                                       MultipartFile[] images, MultipartFile video) {

        if ("IMAGE".equals(contentType)) {
            // 图片内容验证
            if (images != null && images.length > 8) {
                throw new IllegalArgumentException("图片内容最多只能上传8张图片");
            }

            if (images != null) {
                for (MultipartFile image : images) {
                    if (image != null && !image.isEmpty()) {
                        asyncFileService.validateImageFile(image);
                    }
                }
            }

            if (video != null && !video.isEmpty()) {
                throw new IllegalArgumentException("图片内容不能包含视频文件");
            }

        } else if ("VIDEO".equals(contentType)) {
            // 视频内容验证
            if (video == null || video.isEmpty()) {
                throw new IllegalArgumentException("视频内容必须上传视频文件");
            }

            asyncFileService.validateVideoFile(video);

            if (images != null && images.length > 0) {
                boolean hasImages = Arrays.stream(images)
                        .anyMatch(image -> image != null && !image.isEmpty());
                if (hasImages) {
                    throw new IllegalArgumentException("视频内容不能包含图片文件");
                }
            }
        }

        // 验证封面文件（如果提供）
        if (cover != null && !cover.isEmpty()) {
            asyncFileService.validateImageFile(cover);
        }
    }

    /**
     * 构建内容实体对象
     */
    private Content buildContentEntity(Long userId, String contentType, String title, String textContent) {
        Content content = new Content();
        content.setUserId(userId);
        content.setContentType(contentType);
        content.setTitle(title);
        content.setTextContent(textContent);
        content.setLikeCount(0);
        content.setCommentCount(0);
        content.setViewCount(0);
        content.setIsPublished(true);
        content.setIsEsIndexed(false);
        content.setUploadStatus("PENDING"); // 初始状态
        return content;
    }

    /**
     * 插入图片/视频记录到数据库
     */
    private Map<String, Object> insertMediaRecords(Long contentId, String contentType,
                                                   MultipartFile[] images, MultipartFile video) {
        Map<String, Object> mediaInfo = new HashMap<>();
        List<String> imageUrls = new ArrayList<>();
        List<String> videoUrls = new ArrayList<>();
        List<String> imageIds = new ArrayList<>();
        String videoId = null;

        if ("IMAGE".equals(contentType) && images != null) {
            for (MultipartFile image : images) {
                if (image != null && !image.isEmpty()) {
                    String imageUuid = UUID.randomUUID().toString();
                    // 获取原始文件扩展名
                    String extension = getFileExtension(image.getOriginalFilename());
                    String imageUrl = fileServerUrl + "/files-get/springboot/littleRedBook/content/"
                            + contentId + "/images/" + imageUuid + extension;

                    Image imageRecord = new Image();
                    imageRecord.setContentId(contentId);
                    imageRecord.setImageUrl(imageUrl);
                    imageMapper.insert(imageRecord);

                    imageUrls.add(imageUrl);
                    imageIds.add(imageUuid);
                }
            }
        } else if ("VIDEO".equals(contentType) && video != null && !video.isEmpty()) {
            String videoUuid = UUID.randomUUID().toString();
            // 获取原始文件扩展名
            String extension = getFileExtension(video.getOriginalFilename());
            String videoUrl = fileServerUrl + "/files-get/springboot/littleRedBook/content/"
                    + contentId + "/video/" + videoUuid + extension;

            Video videoRecord = new Video();
            videoRecord.setContentId(contentId);
            videoRecord.setVideoUrl(videoUrl);
            videoMapper.insert(videoRecord);

            videoUrls.add(videoUrl);
            videoId = videoUuid;
        }

        mediaInfo.put("imageUrls", imageUrls);
        mediaInfo.put("videoUrls", videoUrls);
        mediaInfo.put("imageIds", imageIds);
        mediaInfo.put("videoId", videoId);

        return mediaInfo;
    }

    /**
     * 保存文件到临时目录
     */
    private String saveTempFile(MultipartFile file, String fileName) throws IOException {
        // 获取项目根目录下的temp目录
        String tempDir = System.getProperty("user.dir") + "/src/main/resources/temp";
        File tempDirFile = new File(tempDir);
        if (!tempDirFile.exists()) {
            tempDirFile.mkdirs();
        }

        // 获取原始文件扩展名
        String extension = getFileExtension(file.getOriginalFilename());
        String tempFilePath = tempDir + "/" + fileName + extension;
        File tempFile = new File(tempFilePath);

        // 保存文件
        file.transferTo(tempFile);

        return tempFilePath;
    }

    /**
     * 更新内容上传状态
     */
    private void updateContentUploadStatus(Long contentId, String status) {
        Content updateContent = new Content();
        updateContent.setId(contentId);
        updateContent.setUploadStatus(status);
        contentMapper.updateById(updateContent);
        log.info("内容上传状态更新，内容ID: {}, 状态: {}", contentId, status);
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (fileName == null) {
            return ".jpg";
        }

        // 使用 File.getName() 只获取文件名部分，去除路径
        String cleanFileName = new File(fileName).getName();

        int lastDotIndex = cleanFileName.lastIndexOf(".");
        if (lastDotIndex > 0 && lastDotIndex < cleanFileName.length() - 1) {
            String extension = cleanFileName.substring(lastDotIndex).toLowerCase();

            // 只允许预定义的安全扩展名
            Set<String> validExtensions = Set.of(".jpg", ".jpeg", ".png", ".gif", ".webp", ".mp4", ".avi", ".mov", ".webm");
            if (validExtensions.contains(extension)) {
                return extension;
            }
        }

        return ".jpg"; // 默认扩展名
    }

    /**
     * 构建创建响应
     */
    private ContentCreateResponseDTO buildCreateResponse(Content content, Map<String, Object> mediaInfo) {
        ContentCreateResponseDTO response = new ContentCreateResponseDTO();
        response.setId(content.getId());
        response.setContentType(content.getContentType());
        response.setTitle(content.getTitle());
        response.setTextContent(content.getTextContent());
        response.setCoverUrl(content.getCoverUrl());
        response.setUploadStatus(content.getUploadStatus());
        response.setLikeCount(content.getLikeCount());
        response.setCommentCount(content.getCommentCount());
        response.setViewCount(content.getViewCount());
        response.setCreatedAt(content.getCreatedAt());

        // 设置媒体文件URL
        response.setImageUrls((List<String>) mediaInfo.get("imageUrls"));
        response.setVideoUrls((List<String>) mediaInfo.get("videoUrls"));
        return response;
    }
}